﻿using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
using CloudShot.Logic;
using CloudShot.Utils;

namespace CloudShot.Editor.CanvasFigures
{
  /// <summary>
  ///   Base class for all draw objects
  /// </summary>
  public abstract class CanvasObject:IBoundingBoxFigure
  {
    private const int DefaultBorderWidth = 3;
    private const int HoverSize = 10;
    private const LineType DefaultLineType = LineType.Solid;

    //protected Color TrackerColor = Color.FromArgb(0xd8, 0xe9, 0xfa);
    protected Color TrackerColor = Color.White;
    protected int TrackerSize = 5;
    protected TrackerType TrackerType = TrackerType.Square;

    protected CanvasObject()
    {
      BorderColor = Color.Black;
      BorderWidth = DefaultBorderWidth;
      LineType = DefaultLineType;
    }

    #region Methods

    public virtual void DrawMarkup(Graphics graphics, Rectangle[] screens)
    {
      if (!IsSelected)
        return;

      DrawTracker(graphics);
    }

    public CanvasObject Clone()
    {
      var clone = CloneIntrenal();
      clone.BorderColor = BorderColor;
      clone.BorderWidth = BorderWidth;
      clone.LineType = LineType;
      return clone;
    }

    protected Rectangle GetHoverRectangle(int handleNumber)
    {
      Point point = GetHandle(handleNumber);
      return point.ExtendToRectangle(HoverSize);
    }

    protected float[] GetDashPattern()
    {
      switch (LineType)
      {
        case LineType.Solid:
          return null;

        case LineType.Dash:
          return new[]
          {
            12f / BorderWidth,
            4f / BorderWidth
          };

        case LineType.Dot:
        {
          if (BorderWidth == 1)
            return new[]
            {
              1f,
              2f
            };

          return new[]
          {
            1f,
            1f
          };
        }
      }

      return null;
    }

    private void DrawTracker(Graphics graphics)
    {
      using (var brush = new SolidBrush(TrackerColor))
      //using (var pen = new Pen(Color.FromArgb(0x5c, 0x5f, 0x65), 1))
      using (var pen = new Pen(Color.Black, 1))
      {
        for (int i = 1; i <= HandlesCount; i++)
        {
          Rectangle rect = GetHandleRectangle(i);

          if (TrackerType == TrackerType.Circle)
          {
            graphics.DrawEllipse(pen, rect);
            graphics.FillEllipse(brush, rect);
          }
          else if (TrackerType == TrackerType.Square)
          {
            graphics.DrawRectangle(pen, rect);
            graphics.FillRectangle(brush, rect);
          }
        }
      }
    }

    private Rectangle GetHandleRectangle(int handleNumber)
    {
      Point point = GetHandle(handleNumber);
      return point.ExtendToRectangle(TrackerSize);
    }

    private DashStyle GetDashStyle()
    {
      switch (LineType)
      {
        case LineType.Solid:
          return DashStyle.Solid;

        case LineType.Dash:
          return DashStyle.Dash;

        case LineType.Dot:
          return DashStyle.Dot;
      }

      return DashStyle.Solid;
    }

    #endregion

    #region Virtual Functions

    /// <summary>
    /// Returns <see cref="Rectangle"/> that includes all elements of <see cref="CanvasObject"/> like move handlers, labels etc.
    /// </summary>
    /// <returns>The <see cref="Rectangle"/> bounding box of <see cref="CanvasObject"/> with all internal elements.</returns>
    public abstract Rectangle GetBoundingBox();

    public abstract void Draw(Graphics graphics);

    /// <summary>
    ///   Hit test.
    ///   Return value: -1 - no hit
    ///   0 - hit anywhere
    ///   > 1 - handle number
    /// </summary>
    public virtual int HitTest(Point point)
    {
      return -1;
    }

    /// <summary>
    ///   Get curesor for the handle
    /// </summary>
    /// <param name="handleNumber"></param>
    /// <returns></returns>
    public virtual Cursor GetHandleCursor(int handleNumber)
    {
      return AppCursors.Default;
    }

    /// <summary>
    ///   Test whether object intersects with rectangle
    /// </summary>
    /// <param name="rectangle"></param>
    /// <returns></returns>
    public virtual bool IntersectsWith(Rectangle rectangle)
    {
      return false;
    }

    /// <summary>
    ///   Move object
    /// </summary>
    /// <param name="deltaX"></param>
    /// <param name="deltaY"></param>
    public virtual void Move(int deltaX, int deltaY) {}

    /// <summary>
    ///   Move handle to the point
    /// </summary>
    /// <param name="point"></param>
    /// <param name="handleNumber"></param>
    public void MoveHandleTo(Point point, int handleNumber)
    {
      MoveHandleTo(point, handleNumber, false);
    }

    /// <summary>
    ///   Move handle to the point
    /// </summary>
    /// <param name="point"></param>
    /// <param name="handleNumber"></param>
    /// <param name="shiftPressed"></param>
    public virtual void MoveHandleTo(Point point, int handleNumber, bool shiftPressed) {}

    /// <summary>
    ///   Normalize object.
    ///   Call this function in the end of object resizing.
    /// </summary>
    public virtual void Normalize() {}

    protected abstract CanvasObject CloneIntrenal();

    protected virtual Pen CreateBorderPen()
    {
      var borderPen = new Pen(BorderColor, BorderWidth)
      {
        DashStyle = GetDashStyle()
      };

      var pattern = GetDashPattern();

      if (pattern != null)
        borderPen.DashPattern = pattern;

      return borderPen;
    }

    protected virtual Point GetHandle(int handleNumber)
    {
      return new Point(0, 0);
    }

    /// <summary>
    ///   Test whether point is inside of the object
    /// </summary>
    /// <param name="point"></param>
    /// <returns></returns>
    protected virtual bool PointInObject(Point point)
    {
      return false;
    }

    #endregion

    #region Properties

    public virtual int HandlesCount
    {
      get { return 0; }
    }

    public bool IsSelected { get; set; }

    public Color BorderColor { get; set; }

    public int BorderWidth { get; set; }

    public LineType LineType { get; set; }

    public int CurrentDragHandle { get; set; }

    public bool IsShowSize { get; set; }

    #endregion
  }
}